/*
Autor: Alexander Savochkin, 2010
New BSD License
*/

#pragma once

#include <boost/array.hpp>
#include <boost/log/common.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include "LogDefinitions.h"

#include "Config.h"
#include "SharedResourceIO.h"
#include "FactoriesKeeper.h"

using boost::array;
using boost::lexical_cast;
using namespace boost::posix_time;

using SRCLF::IO::SharedResourceInput;
using SRCLF::IO::SharedResourceOutput;
using SRCLF::Config::Configuration;
using SRCLF::Config::Section;

namespace SRCLF
{
namespace Demo
{

class TwoDimensionSecondOrder
{
	boost::log::sources::severity_logger< SRCLF::severity_level > logger;

	array<double,2> position, velocity, force; //
	double mass, alpha, cos_alpha, sin_alpha;
public:
	TwoDimensionSecondOrder(const string& resource_id, const Configuration &config);

	void update(double dt);
	void setForce(int dimension, double force);
	double getForce(int dimension);
	double getX(int dimension) const;
};

class TwoDimensionSecondOrderInput : public SharedResourceInput<TwoDimensionSecondOrder>
{
	size_t channel_number;
	ptime last_update;
public:
	TwoDimensionSecondOrderInput(const string& name, const Configuration& config) :
	  SharedResourceInput<TwoDimensionSecondOrder>(config.getSection(Section::input, name).getScalarByKey("resource"), config),
		channel_number( lexical_cast<size_t>( config.getSection(Section::input, name).getScalarByKey("dimension") ) ),
			last_update( microsec_clock::universal_time() ) {};

	double getInput();

	void update(const ptime&); //Corresponding input update used to update state

	void adminCommand(const string& command, string& result);
	void controlCommand(const string& command, string& result);
	void infoCommand(const string& command, string& result);
};

class TwoDimensionSecondOrderOutput : public SharedResourceOutput<TwoDimensionSecondOrder>
{
	size_t channel_number;
public:
	TwoDimensionSecondOrderOutput(const string& name, const Configuration& config) :
		SharedResourceOutput<TwoDimensionSecondOrder>(config.getSection(Section::output, name).getScalarByKey("resource"), config),
			channel_number( lexical_cast<size_t>( config.getSection(Section::output, name).getScalarByKey("dimension") ) ) {};

	void setOutput(double dVal);
	double getOutput();

	void update(const ptime&) {};

	void adminCommand(const string& command, string& result);
	void controlCommand(const string& command, string& result);
	void infoCommand(const string& command, string& result);
};

} //namespace Demo
} //namespace SRCLF
